#include "battery.h"

#define TEMPERATURE_THRESHOLD 0xC0

static battery_t battery = 
{
    .voltagePort = GPIOC,
    .powerChipPort = GPIOC,
    .powerOutputPort = GPIOC,
    .switchKeyPort = GPIOC,
    .shortPort = GPIOD,
    .voltagePin = GPIO_PIN_4,
    .powerChipPin = GPIO_PIN_5,
    .powerOutputPin = GPIO_PIN_7,
    .switchKeyPin = GPIO_PIN_6,    
    .shortPin = GPIO_PIN_4,
    .calculateVoltage = getVolAvgData,
    .status = NORMAL,
};
static battery_t * const pBattery = &battery;
const battery_t * const g_pBattery = &battery;
static double chargingVol = 0;
static double dischargingVol = 0;

//电压的变化率,在普通状态时清0,记录充电后10秒的电压变化
//然后就以这个变化值做加减参考
static double baseRate = 0;

typedef struct filterData_s
{
    double *data;
    double sum;
}filterData_t;

//用的是ADC1通道2
void checkVolInit(void)
{
    ADC1_DeInit();
    ADC1_Init(ADC1_CONVERSIONMODE_SINGLE,ADC1_CHANNEL_2,ADC1_PRESSEL_FCPU_D18,ADC1_EXTTRIG_TIM,DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);
    ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
    ADC1_Cmd(ENABLE);
    ADC1_StartConversion();
}

void batteryInit()
{
    //开关按钮信号输入
    GPIO_Init(pBattery->switchKeyPort,pBattery->switchKeyPin,GPIO_MODE_IN_PU_NO_IT);
    //电压检测输入
    GPIO_Init(pBattery->voltagePort,pBattery->voltagePin,GPIO_MODE_IN_PU_NO_IT);
    //芯片控制自身供电
    GPIO_Init(pBattery->powerChipPort,pBattery->powerChipPin,GPIO_MODE_OUT_PP_LOW_SLOW);
    //电池对外输出
    GPIO_Init(pBattery->powerOutputPort,pBattery->powerOutputPin,GPIO_MODE_OUT_PP_LOW_SLOW);
    //短路保护引脚输出
    GPIO_Init(pBattery->shortPort,pBattery->shortPin,GPIO_MODE_OUT_PP_LOW_SLOW);
    
    checkVolInit();	//配置ADC的检测
}


/*
input:
describe:获取电压值，存在结构体中
return:
*/
void getVolAvgData(void)
{
    static u16 switchAdcCount = 3;
    switchAdcCount++;
    if(switchAdcCount < 4)//这里是防止切换ADC检测产生错误数据做的稳定处理
    {
        //切换后等2个周期稳定
        if(switchAdcCount == 1)
        {
            /* Clear the ADC1 channels */
            ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
            /* Select the ADC1 channel */
            ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_2);
            ADC1_StartConversion();
        }
        else
        {
            ADC1_GetConversionValue();
            ADC1_StartConversion();
        }
        return;
    }
    else if(switchAdcCount < 2000)//所有电压获取都在这里
    {
        static double sum = 0.0f;
        uint8_t nextIndex = pBattery->volIndex + 1;
        uint16_t t_adValue = ADC1_GetConversionValue();
        ADC1_StartConversion();//重新检测
        if(nextIndex == VOLBUF_LENGTH)
        {
            nextIndex = 0;
        }
        
        //一开始旧值里都是0，即为所有的和
        //后面只记录新来的值增减的差即可
        short delta = (t_adValue - pBattery->volDataBuf[pBattery->volIndex]);
        sum += delta;//记录新值与旧值的差
        pBattery->volDataBuf[pBattery->volIndex] = t_adValue;   
        pBattery->volIndex = nextIndex;   
        pBattery->voltage = (sum/VOLBUF_LENGTH);
    }
    else//这里是对温度过高进行保护的
    {
        if(switchAdcCount == 2000)
        {
            /* Clear the ADC1 channels */
            ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
            /* Select the ADC1 channel */
            ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_3);
            ADC1_StartConversion();
        }
        else if(switchAdcCount < 2003)
        {
            ADC1_GetConversionValue();
            ADC1_StartConversion();
        }
        else
        {
            switchAdcCount = 0;
            temProtect();
        }
    }

 
}


/*
input:
describe:判断当前电池的状态
return:
*/
void judgeStatus(void)
{
    //100ms
    static u8 count = 0;
    static u8 prevStatus = 0;
    count++;
    if(count == 15)//0.5s
    {
        count = 0;
        if(pBattery->status == NORMAL)
        {
            static double prevVol = 0;
            static u8 judgeFlag = 0;
            double delta = 0;
            if(prevVol < 0.1)
            {
                prevVol = pBattery->voltage;
            }
            else
            {
                delta = pBattery->voltage - prevVol;
            }

#if 1
            if(judgeFlag == 0)
            {
                if(delta > 0.3)
                {
                    judgeFlag = 1;//充电为1
                    printf(0x3412);
                }
                else if(delta < -0.3)
                {
                    judgeFlag = 2;//放电为2
                    printf(0x2143);
                }
            }
            else
            {
                printf((u16)((pBattery->voltage - pBattery->realVol) * 10));
                
                if(judgeFlag == 1)//充电状态
                {
                    double chargeError = 0;
                    if(pBattery->realVol < LED2_VOL)
                    {
                        chargeError = 0.8;
                    }
                    else
                    {
                        chargeError = 0.5;
                    }
                    if(pBattery->voltage > pBattery->realVol + chargeError)
                    {
                        pBattery->status = CHARGE;
                        chargingVol = prevVol;
                        prevVol = 0;
                    }
                }
                else if(judgeFlag == 2)//放电状态
                {
                    double dischargeError = 0;
                    if(pBattery->realVol < LED2_VOL)
                    {
                        dischargeError = 0.6;
                    }
                    else
                    {
                        dischargeError = 0.9;
                    }
                    if(pBattery->voltage < pBattery->realVol - dischargeError)
                    {
                        pBattery->status = DISCHARGE;
                        dischargingVol = prevVol;
                        prevVol = 0;
                    }
                }
                judgeFlag = 0;
            }          
#endif
            prevVol = pBattery->voltage;
        }
        else if(pBattery->status == CHARGE)
        {
            double delta = pBattery->voltage - chargingVol;
            if(delta < -0.7 || (pBattery->voltage < pBattery->realVol + 0.1))
            {               
                pBattery->status = CHARGE_TO_NORMAL;
            }
            else
            {
                chargingVol = pBattery->voltage;
            }
            
        }
        else if(pBattery->status == DISCHARGE)//放电
        {
            double delta = pBattery->voltage - dischargingVol;
            if(delta > 0.7 || (pBattery->voltage > pBattery->realVol - 0.5))//回到正常状态
            {
                pBattery->status = DISCHARGE_TO_NORMAL;
            }
            else
            {
                //更新放电电压
                dischargingVol = pBattery->voltage;
            }
        }
        
    }
    if(pBattery->status == DISCHARGE_TO_NORMAL)
    {
        static u8 count = 0;
        count++;
        if(count > 1)
        {
            count = 0;
            
            printf((u16)pBattery->voltage);
            printf((u16)pBattery->realVol);
            if(stableJudge())
            {
                double delta = pBattery->voltage - pBattery->realVol;
                printf((u16)(-delta*10) | 0x1000);
                
                //稳定次数记录
                //达到一定次数则直接赋电压
                static u8 stableCount = 0;
                stableCount++;
                if(delta > -0.8 && delta < 0.8)
                {
                    stableCount = 0;
                    pBattery->realVol = pBattery->voltage;
                    pBattery->status = NORMAL;
                }               
                else if(stableCount > 3)
                {
                    stableCount = 0;
                    pBattery->realVol = pBattery->voltage;
                    pBattery->status = NORMAL;
                }
                
            }
            else
            {
                if(pBattery->voltage > pBattery->realVol + 2)
                {
                    pBattery->status = CHARGE;
                }
                else if(pBattery->voltage < dischargingVol - 0.5)
                {
                    pBattery->status = DISCHARGE;
                }
                else if(pBattery->voltage > dischargingVol + 0.5)
                {
                    dischargingVol = pBattery->voltage;
                }
            }
        }
    }
    else if(pBattery->status == CHARGE_TO_NORMAL)
    {
        
        static u8 count = 0;
        count++;
        if(count > 1)
        {
            count = 0;
            
            if(stableJudge())
            {
                printf((u16)pBattery->voltage);
                printf((u16)pBattery->realVol);
                printf((u16)((pBattery->voltage - pBattery->realVol)*10));
                
                //稳定次数记录
                //达到一定次数则直接赋电压
                static u8 stableCount = 0;
                stableCount++;
                if((pBattery->voltage - pBattery->realVol) < 0.8 
                   && (pBattery->voltage - pBattery->realVol) > -0.8)
                {
                    stableCount = 0;
                    pBattery->realVol = pBattery->voltage;
                    pBattery->status = NORMAL;
                }
                else if(stableCount > 3)
                {
                    stableCount = 0;
                    pBattery->realVol = pBattery->voltage;
                    pBattery->status = NORMAL;
                }
            }
            else
            {

#if 1
                if(pBattery->voltage < pBattery->realVol - 2)
                {
                    pBattery->status = DISCHARGE;
                }
                else if(pBattery->voltage > chargingVol + 0.5)
                {
                    pBattery->status = CHARGE;
                }
                else if(pBattery->voltage < chargingVol - 0.5)
                {
                    chargingVol = pBattery->voltage;
                }
#endif
            }
        }
    }
    if(prevStatus != pBattery->status)
    {
        prevStatus = pBattery->status;
        printf(prevStatus);
    }
    volToLedStatus();

}

/*
input:
describe:电压计算，推测当前的电压值
可能误差有时大，需要多种判断结合
return:
*/
void calculateRealVol(void)//50ms
{
    static double prevVol = 0;
    static double baseError = 0;
    static u8 count = 0;
    count++;
    
    if(pBattery->realVol < 0.001)
    {
        if(stableJudge())//开机如果稳定用开机的值
        {
            pBattery->realVol = pBattery->voltage;
            printf(0x1111);
        }
        else
        {
            if(count < 21)
            {
                return;
            }
            count = 0;
            pBattery->realVol = pBattery->voltage;
        }
        printf(((u16)pBattery->realVol));
    }
    
    
    if(pBattery->status == NORMAL)
    {        
        baseRate = 0;
        if(count > 4)
        {
            count = 0;
            if(stableJudge())
            {
                if((pBattery->realVol < pBattery->voltage - 0.2)
                       || (pBattery->realVol > pBattery->voltage + 0.2))
                {
                    pBattery->realVol = pBattery->voltage;
                    printf(((u16)pBattery->realVol) | 0x3000);
                }
                printf(((u16)pBattery->realVol) | 0x8000);
            }
        }

    }    
    else if(pBattery->status == CHARGE)
    {      
        if((count & 15) == 0)//1s更新一次电压
        {
            
            if(prevVol == 0)
            {
                prevVol = pBattery->voltage;
            }
            else
            {

                if(pBattery->realVol < pBattery->voltage - 0.6)
                {
                    if(baseRate > 0)
                    {
                        pBattery->realVol += baseRate * 0.039;
                    }
                    else if(baseRate == 0)
                    {
                        pBattery->realVol += (pBattery->voltage - prevVol) * 0.031;
                    }
                }

                if(count == 0)
                {
                    if(baseRate == 0)
                    {
                        baseRate = pBattery->voltage - prevVol;
                        baseError = 1/(pBattery->voltage - pBattery->realVol);
                    }
                    else
                    {
                        double t_error = pBattery->voltage - pBattery->realVol;
                        if(t_error > 1)
                        {
                            baseRate = baseRate * (baseError*t_error);
                        }
                    }
                }
                else if((count & 47) == 0)
                {
                    printf(((u16)pBattery->realVol) | 0x5000);
                    printf(((u16)pBattery->voltage) | 0x6000);
                }
            }
        
        }        
    }
    else if(pBattery->status == DISCHARGE)//放电状态
    {
        if((count & 15) == 0)//1s更新一次电压
        {

            if(prevVol == 0)
            {
                prevVol = pBattery->voltage;
            }
            else//更新放电速率
            {
                if(pBattery->realVol > pBattery->voltage)
                {
                    if(baseRate < 0)
                    {
                        pBattery->realVol += baseRate * 0.039;
                    }
                    else if(baseRate == 0)
                    {
                        pBattery->realVol += (pBattery->voltage - prevVol) * 0.03;
                    }
                }

                if(count == 0)
                {
                    if(baseRate == 0)
                    {
                        baseRate = pBattery->voltage - prevVol;
                        baseError = -1/(pBattery->voltage - pBattery->realVol);
                    }
                    else
                    {
                        double t_error = pBattery->voltage - pBattery->realVol;
                        if(t_error < -1)
                        {
                            baseRate = baseRate * (baseError*t_error);
                        }
                    }
                }
                else if((count & 47) == 0)
                {
                    printf(((u16)pBattery->realVol) | 0x5000);
                    printf(((u16)pBattery->voltage) | 0x6000);
                }
            }
            
        }
    }
}

/*
input:
describe:判断当前电压是否稳定（一定时间内保持不变）
return:稳定返回1，不稳定返回0
*/
u8 stableJudge()
{
    static u8 stableCount = 0;//电压稳定计时
    static double prevVol = 0;
    stableCount++;
    if(prevVol == 0)
    {
        prevVol = pBattery->voltage;
    }
    if(stableCount > 5)
    {
        stableCount = 0;
        if((pBattery->voltage - prevVol < 0.001)//稳定后
           && (pBattery->voltage - prevVol > -0.001))
        {
            return 1;               
        }
        prevVol = pBattery->voltage;       
    }
    return 0;
}

/*
input:
describe:根据当前电池电压修改led灯状态
return:
*/
void volToLedStatus()
{
    static u8 prevStatus = 0;
    static u8 doOnceFlag = 1;
    u8 status = 0;
    if(pBattery->realVol > LED4_VOL)
    {
        status = 5;
    }
    else if(pBattery->realVol > LED3_VOL)
    {
        status = 4;
    }
    else if(pBattery->realVol > LED2_VOL)
    {
        status = 3;
    }
    else if(pBattery->realVol > LED1_VOL)
    {
        status = 2;
    }
    else
    {
        status = 1;
    }
    //设置刚上电时的状态
    if(prevStatus == 0)
    {
        prevStatus = status;
        printf(prevStatus*0X1111);
    }
    else
    {
        static u8 count = 0;//当状态不同时，给一个时间判断
        if(prevStatus != status)
        {
            count++;
        }
        else
        {
            count = 0;
        }
        if(count > 20)//2S
        {
            prevStatus = status;
            doOnceFlag = 1;
        }
    }
    
    if(prevStatus == 1)
    {

        setLedStatus(0);
        updateLedStatus();         
        if(pBattery->status == CHARGE)
        {           
            g_pLed->controlLed(ON, BUTTON_LED);
            setLedStatus(6);            
        }
        else
        {         
            //if(pBattery->status == DISCHARGE || pBattery->status == NORMAL)
            {
                setLedStatus(5);
            }
            //else
            {
                //g_pLed->controlLed(ON, BUTTON_LED);
            }
        }                   
    }
    else
    {
        if(pBattery->status == CHARGE)//充电和完全没电是闪灯的
        {
            if(doOnceFlag)
            {
                setLedStatus(prevStatus - 1);
                updateLedStatus();            
                setLedStatus(5+prevStatus);
                doOnceFlag = 0;
            }        
        }
        else
        {
            setLedStatus(prevStatus - 1);  
            doOnceFlag = 1;
        }
    }
    updateLedStatus(); 
}




void temProtect()//温度保护
{
    //5S执行一次
    //必须配置一次ADC才能检测准确
    u16 temperature = ADC1_GetConversionValue();
    ADC1_StartConversion();

    if(temperature < TEMPERATURE_THRESHOLD)//温度过高，断开电池输出
    {
        GPIO_WriteLow(g_pBattery->powerOutputPort, g_pBattery->powerOutputPin);
        //关机
        GPIO_WriteLow(g_pBattery->powerChipPort, g_pBattery->powerChipPin);
    }
    //printf(temperature | 0x5000);
}
